#include <jni.h>
#include <android/log.h>
#include <stdio.h>
#include <stdlib.h>

#define LOG_TAG "jnitest_"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,   __VA_ARGS__)

/**
 * 测试野指针问题
 * 写野指针指向的内存，有可能不会马上crash，而是破坏了别处的内存
 */
void makeWildPointException() {
    int *p = NULL; //野指针，未初始化，其指向的地址通常是随机的
    *p = 1; // 写野指针指向的内存，有可能不会马上crash，而是破坏了别处的内存
}

/**
 * 测试数组越界
 * 数组越界，有可能不会马上crash，而是破坏了别处的内存
 */
void makeOutOfBoundException() {
    int arr[10];
    arr[20] = 1; //数组越界，有可能不会马上crash，而是破坏了别处的内存
}

/**
 * 除数除以0，产生SIGFPE信号，导致crash
 *
 */
int makeDividedZero() {
    int a = 1;
    int b = 0;
    int c = a/b;
    return  c;
}

/**
 * 格式化参数错误，可能会导致非法的内存访问，从而造成crash
 */
void makeFormatException() {
    char text[200];
    snprintf(text, 200, "Valid %u, invalid %i %s", 1);//format格式不匹配

    LOGD(text);
}

/**
 * buffer溢出，产生SIGABRT或者SIGSEGV，造成Crash
 */
void makeOutOfBuffer() {
    char szBuffer[10];
    //由于函数栈是从高地址往低地址创建，而sprintf是从低地址往高地址打印字符，
    //如果超出了缓冲区的大小，函数的栈帧会被破坏，在函数返回是会跳到未知的地址上，
    //基本上都会造成访问异常，从而产生SIGABRT或者SIGSEGV，造成Crash
    sprintf(szBuffer, "Stack Buffer Overrun!1111111111111111111111", "11111111111111111111111");

    LOGD(szBuffer);
}

/**
 * 生成SIGABRT
 * @param env
 */
void makeSigAbrt() {
    //if ((*env)->ExceptionOccurred(env) != 0) {
        //动态库在内部运行出现错误是，大都会主动abort，终止运行
        abort(); //给当前进程发送信号SIGABRT
    //}
}

JNIEXPORT jstring JNICALL
Java_com_iflytek_jnitest_jnitest_TestJni_getMsgFromJni(JNIEnv *env, jobject instance)
{
    LOGD("Java_com_iflytek_jnitest_jnitest_TestJni_getMsgFromJni");

    char str[100];
    strcpy(str, "hello world from jni");

    return (*env)->NewStringUTF(env, str);
}

JNIEXPORT void JNICALL
Java_com_iflytek_jnitest_jnitest_TestJni_makeWildPointException(JNIEnv *env, jclass type)
{
    LOGD("Java_com_iflytek_jnitest_jnitest_TestJni_makeWildPointException");
    makeWildPointException();
}

JNIEXPORT void JNICALL
Java_com_iflytek_jnitest_jnitest_TestJni_makeOutOfBoundException(JNIEnv *env, jclass type)
{
    LOGD("Java_com_iflytek_jnitest_jnitest_TestJni_makeOutOfBoundException");
    makeOutOfBoundException();

}

JNIEXPORT void JNICALL
Java_com_iflytek_jnitest_jnitest_TestJni_makeDividedZero(JNIEnv *env, jclass type)
{
    LOGD("Java_com_iflytek_jnitest_jnitest_TestJni_makeDividedZero");
    makeDividedZero();

}

JNIEXPORT void JNICALL
Java_com_iflytek_jnitest_jnitest_TestJni_makeFormatException(JNIEnv *env, jclass type)
{
    LOGD("Java_com_iflytek_jnitest_jnitest_TestJni_makeFormatException");
    makeFormatException();
}

JNIEXPORT void JNICALL
Java_com_iflytek_jnitest_jnitest_TestJni_makeOutOfBuffer(JNIEnv *env, jclass type)
{
    LOGD("Java_com_iflytek_jnitest_jnitest_TestJni_makeOutOfBuffer");
    makeOutOfBuffer();
}

JNIEXPORT void JNICALL
Java_com_iflytek_jnitest_jnitest_TestJni_makeSigAbrt(JNIEnv *env, jclass type)
{
    LOGD("Java_com_iflytek_jnitest_jnitest_TestJni_makeSigAbrt");
    makeSigAbrt();
}